'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

var app = angular.module("myApp", ['ui.bootstrap', 'ui.bootstrap.treeview']);

app.config(['$compileProvider', function ($compileProvider) {
    $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|blob|sms|data):/);
    // Angular v1.2 之前使用 $compileProvider.urlSanitizationWhitelist(...)
}]);

app.controller("manageController2", ['$scope', '$compile', '$sce', function ($scope, $compile, $sce) {
    $scope.query = {
        fault: FaultNode.faults[0]
    };

    $scope.filterOfFault = function (fault) {
        if ($scope.query.faultType && $scope.query.faultType != '') {
            if (fault.faultCategory != $scope.query.faultType) {
                return false;
            }
        }
        if ($scope.query.faultModule && $scope.query.faultModule != '') {
            if (fault.faultModule != $scope.query.faultModule) {
                return false;
            }
        }
        return true;
    };

    $scope.faultModules = [];
    $scope.refreshModules = function () {
        getCache("fault_module", function (val) {
            $scope.faultModules = val.map(function (x) {
                if (x.indexOf(':') < 0) {
                    return {
                        category: '',
                        name: x
                    };
                }
                var arr = x.split(':', 2);
                return {
                    category: arr[0],
                    name: arr[1]
                };
            });
            $scope.faultModules.splice(0, 0, '');
        }, function (callback, cache, name) {
            getConfigure('module', function (data) {
                cache[name] = {
                    lastTimestamp: new Date().getTime(),
                    value: data
                };
                callback(data);
            });
        }, 5000);
    };
    $scope.refreshModules();

    $scope.refreshFaults = function () {
        FaultNode.loadFaults.callbacks = [function () {
            return $scope.faults = FaultNode.faults;
        }];
        FaultNode.loadFaults();

        ComponentNode.loadComponents();

        $scope.refreshModules();
    };

    $scope.sortByOutId = function (f) {
        if (!f.outId) {
            return 0;
        }
        return parseInt(f.outId, 10);
    };

    $scope.toJSON = function (val) {
        return angular.toJson(val, true);
    };

    $scope.graphModel = 1;

    // $scope.faults=FaultNode.faults;
    FaultNode.loadFaults.callbacks.push(function () {
        return $scope.faults = FaultNode.faults;
    });
    FaultNode.loadFaults.callbacks.push(function () {
        return $scope.query.fault = FaultNode.faults[0];
    });
    FaultNode.loadFaults();

    $scope.components = ComponentNode.components;
    ComponentNode.loadComponents.callbacks.push(function () {
        return $scope.components = ComponentNode.components;
    });
    ComponentNode.loadComponents();

    $scope.graphTree = new TreeView();
    $scope.d3Graph = new D3Graph();
    $scope.$watch('query', function () {
        console.info($scope.query);
        $scope.reloadData();
    }, true);

    $scope.$watch('graphTree.selectedNode', function () {
        var data = $scope.graphTree.selectedNode;
        if ($scope.graph) {
            var template = $scope.graph.getNode(data.referId).getReadonlyTemplate(data.referEdge, $scope.graph);
            var tp = $compile(template)($scope);
            angular.element("#nodeDetail2").html("").append(tp);
        }
    }, true);

    $scope.reloadData = function () {
        if ($scope.query.fault) Graph.loadGraph($scope.query.fault.id, function (g) {
            var session = neo4jService.getSession();
            g.markSubGraph().then(function () {
                return Promise.all([].concat(_toConsumableArray(g.nodes.values())).filter(function (n) {
                    return n.$is_sub_graph && !n.$removed;
                }).map(function (n) {
                    return new Promise(function (resolve, reject) {
                        return MyNode.getAncestors(session, n.id).then(function (nd) {
                            nd.filter(function (ndd) {
                                return ndd.$type == "Fault";
                            }).forEach(function (nddx) {
                                n.$faults = n.$faults || new Set();
                                n.$faults.add(nddx);
                            });
                            resolve();
                        });
                    });
                }));
            }).then(function () {
                return Promise.all([].concat(_toConsumableArray(g.nodes.values())).filter(function (n) {
                    return (n.$is_sub_graph || n.$type == "Fault") && n.$type != 'ReasonGroup';
                }).map(function (n) {
                    return new Promise(function (resolve, reject) {
                        if (n.$is_sub_graph) {
                            $.get('http://127.0.0.1:8080/feature/' + n.id, function (data) {
                                n = $.extend(n, data);
                                g.addNode(n);
                                resolve(n);
                            });
                        } else {
                            $.get('http://127.0.0.1:8080/reason/' + n.id, function (data) {
                                n = $.extend(n, data);
                                g.addNode(n);
                                resolve(n);
                            });
                        }
                    });
                }));
            }).then(function () {
                $scope.graph = g;
                $scope.graphTree.nodes = [$scope.graph.toJsonTree()];
                $scope.graphTree.collapseAll();
                console.info($scope.graphTree);

                $scope.$apply();
                if ($scope.graphModel == 1) {
                    $scope.d3Graph.reset();
                }
                $scope.d3Graph.refresh($scope.graph);
            });
        });
    };

    $scope.displayAllTree = function () {
        // let gs = [];
        // let gts =  FaultNode.faults.length;
        // let gtn = 0;
        // for (let f of FaultNode.faults){
        //     Graph.loadGraph(f.id,(g)=>{
        //         gs.push(g);
        //         gtn ++;
        //         if(gtn==gts){
        //             $scope.graphTree.nodes = gs.map(g=>g.toJsonTree());
        //             $scope.graphTree.collapseAll();
        //         }
        //     });
        // }
        Graph.loadAllGraph().then(function (graphGroup) {
            $scope.graphTree.nodes = [graphGroup.toJsonTree()];
            $scope.graphTree.collapseAll();

            $scope.$apply();
            if ($scope.graphModel == 1) {
                $scope.d3Graph.reset();
            }
            $scope.d3Graph.refresh(graphGroup);
        });
    };

    $scope.href = '';
    $scope.generateDownloadHref = function () {
        // let serializer = new XMLSerializer();
        // let xmlString = serializer.serializeToString(d3.select('svg').node());
        // let imgData = 'data:image/svg+xml;base64,' + btoa(xmlString);
        var svg = d3.select("svg").attr("title", "知识库").attr("version", 1.1).attr("xmlns", "http://www.w3.org/2000/svg").node().innerHTML;
        var cover = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" class="neo4jd3-graph" version="1.0"><defs>\n    <style type="text/css"><![CDATA[\n       * {\n  margin: 0px;\n  padding: 0px;\n}\n\nbody {\n  font: 13px \'Helvetica Neue\',Helvetica,Arial,sans-serif;\n  font-size: 20px;\n}\n\n.neo4jd3-graph {\n  border: 1px solid #ddd;\n  border-radius: 5px;\n}\n\n.neo4jd3-info {\n  font-size: 16px;\n  padding: 10px;\n  position: absolute;\n}\n.neo4jd3-info a {\n  border: 1px solid;\n  display: inline-block;\n  font-size: 14px;\n  line-height: 1.428571429;\n  margin-left: 5px;\n  margin-top: 5px;\n  padding: 6px 12px;\n}\n.neo4jd3-info a.class {\n  color: white;\n}\n.neo4jd3-info a.property {\n  background-color: #fff;\n  border-color: #ccc;\n  color: #333;\n}\n.neo4jd3-info a.btn {\n  margin-left: 5px;\n  margin-top: 5px;\n  opacity: 1;\n}\n.neo4jd3-info a.info {\n  background-color: #a5abb6;\n  border: 1px solid #9aa1ac;\n  color: white;\n}\n\n.node.node-highlighted .ring {\n  -ms-filter: \'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)\';\n  filter: alpha(opacity=50);\n  opacity: .5;\n  stroke: #888;\n  stroke-width: 12px;\n}\n.node .outline {\n  cursor: pointer;\n  fill: #a5abb6;\n  pointer-events: all;\n  stroke: #9aa1ac;\n  stroke-width: 2px;\n}\n.node .ring {\n  fill: none;\n  -ms-filter: \'progid:DXImageTransform.Microsoft.Alpha(Opacity=0)\';\n  filter: alpha(opacity=0);\n  opacity: 0;\n  stroke: #6ac6ff;\n  stroke-width: 8px;\n}\n.node .text.icon {\n  font-family: FontAwesome;\n}\n\n.node.selected .ring,\n.node:hover .ring {\n  -ms-filter: \'progid:DXImageTransform.Microsoft.Alpha(Opacity=30)\';\n  filter: alpha(opacity=30);\n  opacity: .3;\n}\n\n.relationship {\n  cursor: default;\n}\n.relationship line {\n  stroke: #aaa;\n}\n.relationship .outline {\n  cursor: default;\n}\n.relationship .overlay {\n  cursor: default;\n  fill: #6ac6ff;\n  -ms-filter: \'progid:DXImageTransform.Microsoft.Alpha(Opacity=0)\';\n  filter: alpha(opacity=0);\n  opacity: 0;\n}\n.relationship text {\n  cursor: default;\n}\n\n.relationship.selected .overlay,\n.relationship:hover .overlay {\n  -ms-filter: \'progid:DXImageTransform.Microsoft.Alpha(Opacity=30)\';\n  filter: alpha(opacity=30);\n  opacity: .3;\n}\n\nsvg {\n  cursor: move;\n}\n\n    ]]></style>\n  </defs>\n  ' + svg + '\n  </svg>';
        var blob = new Blob([cover]);
        $scope.href = URL.createObjectURL(blob);
        // $scope.href ="data:image/svg+xml;base64,\n" + btoa(unescape(encodeURIComponent(cover)));
    };
}]);

var D3Graph = function () {
    function D3Graph() {
        _classCallCheck(this, D3Graph);

        this.reset();
    }

    _createClass(D3Graph, [{
        key: 'refresh',
        value: function refresh(graph) {
            this.d3data = new D3Transfer(graph);
            // d3.selectAll('#neo4jd3 .relationship').remove();
            // d3.selectAll('#neo4jd3 .node').remove();
            this.neo4jd3.updateWithD3Data(this.d3data);
        }
    }, {
        key: 'reset',
        value: function reset() {
            if (this.neo4jd3) {
                delete this.neo4jd3;
            }
            d3.selectAll('#neo4jd3 g.relationships *').remove();
            d3.selectAll('#neo4jd3 g.nodes *').remove();
            this.neo4jd3 = new Neo4jd3('#neo4jd3', {
                highlight: [],
                minCollision: 60,
                nodeRadius: 25,
                neo4jData: {
                    "results": [{
                        "columns": ["user", "entity"],
                        "data": [{
                            "graph": {
                                "nodes": [],
                                "relationships": []
                            }
                        }]
                    }]
                },
                onNodeDoubleClick: function onNodeDoubleClick(node) {
                    switch (node.id) {
                        case '25':
                            // Google
                            window.open(node.properties.url, '_blank');
                            break;
                        default:
                            var maxNodes = 5,
                                data = neo4jd3.randomD3Data(node, maxNodes);
                            neo4jd3.updateWithD3Data(data);
                            break;
                    }
                },
                onRelationshipDoubleClick: function onRelationshipDoubleClick(relationship) {
                    console.log('double click on relationship: ' + JSON.stringify(relationship));
                },
                zoomFit: true
            });
        }
    }]);

    return D3Graph;
}();

var D3SimpleForceChart = function D3SimpleForceChart(chartRef, data) {
    _classCallCheck(this, D3SimpleForceChart);

    this.chartRef = document.querySelector(chartRef);
    this.data = data;
    var containerWidth = this.chartRef.parentElement.offsetWidth;
    var margin = { top: 60, right: 60, bottom: 60, left: 60 };
    var width = containerWidth - margin.left - margin.right;
    var height = 700 - margin.top - margin.bottom;
    var chart = d3.select(this.chartRef).attr('width', width + margin.left + margin.right).attr('height', height + margin.top + margin.bottom);
    var g = chart.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); // 设最外包层在总图上的相对位置
    var simulation = d3.forceSimulation() // 构建力导向图
    .force('link', d3.forceLink().id(function (d, i) {
        return i;
    }).distance(function (d) {
        return d.value * 50;
    })).force('charge', d3.forceManyBody()).force('center', d3.forceCenter(width / 2, height / 2)).alpha(1).alphaDecay(0.001);

    var z = d3.scaleOrdinal(d3.schemeCategory10); // 通用线条的颜色

    var link = g.append('g') // 画连接线
    .attr('class', 'links').selectAll('line').data(data.edges).enter().append('line');

    var linkText = g.append('g') // 画连接连上面的关系文字
    .attr('class', 'link-text').selectAll('text').data(data.edges).enter().append('text').text(function (d) {
        return d.relation;
    });

    var node = g.append('g') // 画圆圈和文字
    .attr('class', 'nodes').selectAll('g').data(data.nodes).enter().append('g')
    // .on('mouseover', function(d, i) {
    //     //显示连接线上的文字
    //     linkText.style('fill-opacity', function(edge) {
    //         if (edge.source === d || edge.target === d) {
    //             return 1
    //         }
    //     });
    //     //连接线加粗
    //     link
    //         .style('stroke-width', function(edge) {
    //             if (edge.source === d || edge.target === d) {
    //                 return '2px'
    //             }
    //         })
    //         .style('stroke', function(edge) {
    //             if (edge.source === d || edge.target === d) {
    //                 return '#000'
    //             }
    //         })
    // })
    // .on('mouseout', function(d, i) {
    //     //隐去连接线上的文字
    //     linkText.style('fill-opacity', function(edge) {
    //         if (edge.source === d || edge.target === d) {
    //             return 0
    //         }
    //     });
    //     //连接线减粗
    //     link
    //         .style('stroke-width', function(edge) {
    //             if (edge.source === d || edge.target === d) {
    //                 return '1px'
    //             }
    //         })
    //         .style('stroke', function(edge) {
    //             if (edge.source === d || edge.target === d) {
    //                 return '#ddd'
    //             }
    //         })
    // })
    .call(d3.drag().on('start', dragstarted).on('drag', dragged).on('end', dragended));

    //显示连接线上的文字
    linkText.style('fill-opacity', 1);

    link.style('stroke-width', function (edge) {
        // if (edge.source === d || edge.target === d) {
        return '2px';
        // }
    }).style('stroke', function (edge) {
        // if (edge.source === d || edge.target === d) {
        return '#000';
        // }
    });

    node.append('circle').attr('r', 45).attr('fill', function (d, i) {
        return z(i);
    });

    node.append('text').attr('fill', function (d, i) {
        return z(i);
    }).attr('y', -20).attr('dy', '.71em').text(function (d) {
        return d.name;
    });

    simulation // 初始化力导向图
    .nodes(data.nodes).on('tick', ticked);

    simulation.force('link').links(data.edges);

    chart.append('g') // 输出标题
    .attr('class', 'bar--title').append('text').attr('fill', '#000').attr('font-size', '16px').attr('font-weight', '700').attr('text-anchor', 'middle').attr('x', containerWidth / 2).attr('y', 20).text('人物关系图');

    function ticked() {
        // 力导向图变化函数，让力学图不断更新
        link.attr('x1', function (d) {
            return d.source.x;
        }).attr('y1', function (d) {
            return d.source.y;
        }).attr('x2', function (d) {
            return d.target.x;
        }).attr('y2', function (d) {
            return d.target.y;
        });
        linkText.attr('x', function (d) {
            return (d.source.x + d.target.x) / 2;
        }).attr('y', function (d) {
            return (d.source.y + d.target.y) / 2;
        });
        node.attr('transform', function (d) {
            return 'translate(' + d.x + ',' + d.y + ')';
        });
    }

    function dragstarted(d) {
        if (!d3.event.active) {
            simulation.alphaTarget(0.3).restart();
        }
        d.fx = d.x;
        d.fy = d.y;
    }

    function dragged(d) {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
    }

    function dragended(d) {
        if (!d3.event.active) {
            simulation.alphaTarget(0);
        }
        d.fx = null;
        d.fy = null;
    }
};

var D3Transfer = function D3Transfer(graph) {
    _classCallCheck(this, D3Transfer);

    this.nodes = [].concat(_toConsumableArray(graph.nodes.values())).map(function (node) {
        return {
            id: node.id,
            labels: [node.$type],
            properties: node
        };
    });
    this.relationships = graph.edges.map(function (edge) {
        var edgeProps = $.extend({}, edge);
        delete edgeProps.graph;

        var fromNode = graph.getNode(edge.from);
        var endNode = graph.getNode(edge.to);
        var fault = graph.getRoot();

        if (fromNode == null || endNode == null) {
            return null;
        }

        if (endNode.$is_sub_graph) {
            edgeProps["概率"] = (endNode.defaultFrequency(fault.id)[fault.id] / endNode.defaultQuantum() * 100).toFixed(2) + '%';
        }

        if (endNode.$type == 'Reason') {
            if (fault.frequency != null && fault.quantum != null) {
                edgeProps["概率"] = (fault.frequency[edge.to] / fault.quantum * 100).toFixed(2) + '%';
            } else {
                edgeProps["概率"] = (endNode.probability * 100).toFixed(2) + '%';
            }
        }

        return {
            "id": edge.id,
            "type": edge.linkType(),
            "startNode": edge.from,
            "endNode": edge.to,
            "properties": edgeProps,
            "source": edge.from,
            "target": edge.to,
            "linknum": 1
        };
    }).filter(function (x) {
        return x != null;
    });
};

var GraphTransfer = function () {
    function GraphTransfer(g) {
        var _this = this;

        _classCallCheck(this, GraphTransfer);

        this.g = g;
        this.nodes = [].concat(_toConsumableArray(g.nodes.values()));
        this.edges = g.edges.map(function (edge) {
            return {
                source: GraphTransfer.indexOf(_this.nodes, edge.from),
                target: GraphTransfer.indexOf(_this.nodes, edge.to),
                relation: edge.linkType(),
                id: edge.id,
                value: GraphTransfer.weightOfLink(edge.linkType())
            };
        });
    }

    _createClass(GraphTransfer, null, [{
        key: 'indexOf',
        value: function indexOf(nodes, id) {
            return nodes.findIndex(function (node) {
                return node.id == id;
            });
        }
    }, {
        key: 'weightOfLink',
        value: function weightOfLink(linkType) {
            switch (linkType) {
                case 'hasFeatures':
                case 'hasReasons':
                    return 10;
                case 'contains':
                    return 6;
                case 'of':
                    return 3;
            }
            return 8;
        }
    }]);

    return GraphTransfer;
}();

// 找到支持的方法, 使用需要全屏的 element 调用


function launchFullScreen(element) {
    if (element.requestFullscreen) {
        element.requestFullscreen();
    } else if (element.mozRequestFullScreen) {
        element.mozRequestFullScreen();
    } else if (element.webkitRequestFullscreen) {
        element.webkitRequestFullscreen();
    } else if (element.msRequestFullscreen) {
        element.msRequestFullscreen();
    }
}

// 退出 fullscreen
function exitFullscreen() {
    if (document.exitFullscreen) {
        document.exitFullscreen();
    } else if (document.mozExitFullScreen) {
        document.mozExitFullScreen();
    } else if (document.webkitExitFullscreen) {
        document.webkitExitFullscreen();
    }
}
